<template>
	<view class="upload_box111">
		<view class="media_box" v-for="(fileItem, fileIndex) in fileListByExhibited" :key="fileIndex">
			<image class="media" v-if="fileItem.type == 'image'" :src="fileItem.url" @tap="previewImage(fileIndex)"></image>
			<view class="video_box" v-else-if="fileItem.type == 'video'">
				<cvideo :src="fileItem.url" :cover="fileItem.cover"></cvideo>
				<view class="cover_edit" v-if="cover" @tap.stop="editCover(fileIndex)">上传封面</view>
			</view>
			<image class="media_delete" src="https://xjs-oss-prod.oss-cn-shenzhen.aliyuncs.com/xjs-static/icon-100.png" @tap="deleteFile(fileIndex)"></image>
		</view>
		<view class="uploader_box media_box" @tap="onUpload">
			<image class="uploader_icon_add" src="https://xjs-oss-prod.oss-cn-shenzhen.aliyuncs.com/xjs-static/icon-97.png"></image>
		</view>
		
		<uni-popup ref="popupRef" type="bottom" :mask-click="false">
			<view class="upload_popup">
				<view class="popup_header">请选择上传文件类型</view>
				<view class="popup_content">
					<view class="popup_button" @tap="selectFileType('image')">图片</view>
					<view class="popup_button" @tap="selectFileType('video')">视频</view>
					<view class="popup_button" @tap="closePopup">取消</view>
				</view>
			</view>
		</uni-popup>
	</view>
</template>

<script setup>
import { ref, defineEmits, watch, computed, } from 'vue';
import config from '@/config/index.ts';
import { useUserStoreToRefs } from '@/store/useUserStore';
import { accredit } from '@/hooks/useAppPermission/index';
const { access_token } = useUserStoreToRefs();
const emit = defineEmits(['update:modelValue']);

// 组件参数说明
const props = defineProps({
	// 注意modelValue从父组件传入的数组必须用ref声明，或者reactive声明时，变量整体重新赋值必须嵌套reactive，否则无法监听响应
	// reactive声明重新赋值没有包裹reactive导致的问题表现为：图片上传成功，数据变更，但是没有渲染，因为无法监听，没有触发更新
	modelValue: {
		type: Array,
		required: true,
		default: []
	},
	// 文件类型 image 图片 video 视频
	// @example mediaType="['image', 'video']"
	mediaType: {
		type: Array,
		default: ['image']
	},
	// 图片和视频选择的来源 album相册或camera相机
	// @example sourceType="['album', 'camera']"
	sourceType: {
		type: Array,
		default: ['album']
	},
	// 上传文件最大数量
	count: {
		type: Number,
		default: 9
	},
	// 上传接口，需要带/api
	uploadUrl: {
		type: String
	},
	// 是否上传视频封面
	cover: {
		type: Boolean,
		default: false
	}
});

const popupRef = ref();
// fileType image 图片 video视频
const fileType = ref('image');
const selectedMethodList = {
	image: chooseImage,
	video: chooseVideo
};

const init = () => {
	const mediaType = props.mediaType[0];
	const isAvailableValue = ['image', 'video'].includes(mediaType);
	if (isAvailableValue) {
		fileType.value = mediaType;
	}
};
init();

const closePopup = () => {
	popupRef.value.close();
};

const onUpload = async () => {
	// #ifdef APP
	const status = await accredit('CAMERA')
	if (status != 1) return
	const status2 = await accredit('READ_EXTERNAL_STORAGE')
	if (status2 != 1) return
	// #endif
	if (props.modelValue.length >= props.count) {
		uni.showToast({
			icon: 'none',
			title: '上传数量达到最大限制'
		});
		return;
	}
	const length = props.mediaType.length;
	if (length == 0 || length > 1) {
		popupRef.value.open();
	} else {
		selectFiles(props.count - props.modelValue.length);
	}
};

// type: image 、video
// url 图片路径
const fileListByExhibited = computed(() => {
	if (!(props.modelValue instanceof Array) && props.modelValue.length < 1) return [];
	const isVideo = props.mediaType.includes('video');
	return props.modelValue.map((item) => {
		let info = {};
		if (props.cover && isVideo) {
			info = {
				url: item.url,
				cover: item.cover,
				type: judgeFileType(getExt(item.url))
			};
		} else {
			info = {
				url: item,
				type: judgeFileType(getExt(item))
			};
		}
		return info;
	});
});

const previewImage = (fileIndex) => {
	const url = props.modelValue[fileIndex];
	uni.previewImage({
		urls: [url],
		current: 0,
		fail: function (err) {
			console.error('Failed to start preview:', err);
		}
	});
};

const deleteFile = (index) => {
	uni.showModal({
		title: '提示',
		content: '是否删除该文件',
		success: function (res) {
			if (res.confirm) {
				props.modelValue.splice(index, 1);
			} else if (res.cancel) {
				console.log('用户点击取消');
			}
		}
	});
};

const editCover = (fileIndex) => {
	chooseCover(fileIndex);
};

const selectFiles = (count) => {
	const fn = selectedMethodList[fileType.value];
	fn(count);
};

function chooseImage(count) {
	uni.chooseImage({
		count: count > 9 ? 9 : count, // 最多可以选择的文件个数，与最大上传数量无关。IOS限制一次性最多选9张
		sourceType: props.sourceType,
		success(res) {
			const tempFiles = res.tempFiles || [];
			tempFiles.forEach((fileItem) => {
				// 小程序一次只能上传一张，所以要循环调用
				uploadFileToList(fileItem.path);
			});
		}
	});
}

function chooseCover(fileIndex) {
	uni.chooseImage({
		count: 1, // 最多可以选择的文件个数，与最大上传数量无关。IOS限制一次性最多选9张
		sourceType: ['album'],
		success(res) {
			const tempFiles = res.tempFiles || [];
			tempFiles.forEach((fileItem) => {
				// 小程序一次只能上传一张，所以要循环调用
				uploadFile(fileItem.path).then((data) => {
					props.modelValue[fileIndex].cover = data;
				});
			});
		}
	});
}

function chooseVideo() {
	uni.chooseVideo({
		sourceType: props.sourceType,
		success: function (res) {
			console.log('res', res);
			console.log('res.tempFilePath', res.tempFilePath);
			uploadFileToList(res.tempFilePath);
		}
	});
}

const uploadFileToList = (filePath) => {
	const isVideo = props.mediaType.includes('video');
	uploadFile(filePath).then((data) => {
		if (props.cover && isVideo) {
			props.modelValue.push({
				url: data,
				cover: ''
			});
		} else {
			props.modelValue.push(data);
		}
		emit('update:modelValue', props.modelValue);
	});
};

const uploadFile = (filePath) => {
	return new Promise((res, rej) => {
		uni.uploadFile({
			url: `${config.api}${props.uploadUrl}`,
			filePath: filePath,
			name: 'file',
			header: {
				Authorization: access_token.value ? 'Bearer ' + access_token.value : 'Basic bWFsbC1hcHA6bWFsbC1hcHA=',
				'x-flow-id': new Date().getTime()
			},
			success: (uploadFileRes) => {
				let data = {};
				try {
					data = JSON.parse(uploadFileRes.data);
				} catch (error) {
					data = {};
				}

				if (data.code == 0) {
					res(data.data);
				} else {
					uni.showToast({
						icon: 'none',
						title: '上传失败，请重新上传'
					});
					rej();
				}
			},
			fail: () => {
				uni.showToast({
					icon: 'none',
					title: '上传失败，请重新上传'
				});
				rej();
			}
		});
	});
};

// 获取扩展名
const getExt = (str) => {
	if (!(typeof str == 'string')) return '';
	const strList = str.split('.');
	const lastIndex = strList.length - 1 > -1 ? strList.length - 1 : 0;
	if (lastIndex == 0) return '';
	const ext = strList[lastIndex];
	return ext;
};

const judgeFileType = (ext) => {
	if (!(typeof ext == 'string')) return '';
	// 常见图片后缀名
	const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff', 'svg'];

	// 常见视频后缀名
	const videoExtensions = ['mp4', 'avi', 'mov', 'mkv', 'flv', 'wmv', 'webm', 'mpeg', 'mpg', '3gp'];

	if (imageExtensions.includes(ext.toLowerCase())) {
		return 'image';
	} else if (videoExtensions.includes(ext.toLowerCase())) {
		return 'video';
	}
};

const selectFileType = (type) => {
	// type image 图片 video视频
	fileType.value = type;
	selectFiles(props.count - props.modelValue.length);
	closePopup();
};
</script>

<style lang="scss" scoped>
	
.upload_box111 {
	width: 100%;
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	grid-column-gap: 20rpx;
	grid-row-gap: 20rpx;
	box-sizing: border-box;

	.media_box {
		// width: 200rpx;
		height: 200rpx;
		position: relative;

		.media {
			width: 100%;
			height: 100%;
		}

		.video_box {
			width: 100%;
			height: 100%;
			position: relative;

			.video_content {
				width: 100%;
				height: 100%;
				background-color: #1a1a1a;
				display: flex;
				justify-content: center;
				align-items: center;
				
				.video_content_icon {
					width: 60rpx;
					height: 60rpx;
				}
			}
			
			.cover_image_box {
				width: 100%;
				height: 100%;
				position: absolute;
				bottom: 0;
				left: 0;
				
				.cover_image {
					width: 100%;
					height: 100%;
				}
				.cover_image_icon {
					position: absolute;
					top: 50%;
					left: 50%;
					transform: translate(-50%, -50%);
					width: 60rpx;
					height: 60rpx;
				}
			}

			.cover_edit {
				width: 100%;
				font-size: 24rpx;
				color: #fff;
				padding: 8rpx 0;
				text-align: center;
				position: absolute;
				bottom: 0;
				left: 0;
				z-index: 9;
				background-color: rgba(26,26,26,0.2);
			}
		}
		.media_delete {
			width: 32rpx;
			height: 32rpx;
			border-radius: 50%;
			position: absolute;
			right: 16rpx;
			top: 16rpx;
			z-index: 9;
			background-color: #fff;
		}
	}

	.uploader_box {
		background: #f9f6f6;
		display: flex;
		align-items: center;
		justify-content: center;

		.uploader_icon_add {
			width: 64rpx;
			height: 64rpx;
		}
	}
}

.upload_popup {
	padding: 48rpx 32rpx;
	background-color: #fff;
	border-radius: 24rpx 24rpx 0 0;

	.popup_header {
		font-weight: bold;
		font-size: 36rpx;
		color: #1a1a1a;
		text-align: center;
		margin-bottom: 64rpx;
	}

	.popup_content {
		margin-top: 64rpx;

		.popup_button {
			height: 92rpx;
			border-radius: 45rpx;
			line-height: 92rpx;
			text-align: center;
			font-size: 30rpx;
			color: #5c5e5e;
			margin-bottom: 40rpx;
			background-color: #f5f6f7;
		}
	}
}
</style>
